using System;
using System.Runtime.Serialization;
using ServiceStack.Text;

namespace NodaTime.Serialization.ServiceStackText
{
    public static class ServiceStackFallbackDeserializers
    {
        public static Instant ToInstant(string text)
        {
            var dateTimeOffset = DeserializeStruct<DateTimeOffset>(text);
            var instant = Instant.FromDateTimeOffset(dateTimeOffset);
            return instant;
        }
        public static LocalTime ToLocalTime(string text)
        {
            var dateTime = DeserializeStruct<DateTime>(text);
            var localTime = LocalTime.FromTicksSinceMidnight(dateTime.TimeOfDay.Ticks);
            return localTime;
        }

        public static LocalDate ToLocalDate(string text)
        {
            var dateTimeOffset = DeserializeStruct<DateTimeOffset>(text);
            var localDate = OffsetDateTime.FromDateTimeOffset(dateTimeOffset).Date;
            return localDate;
        }

        public static LocalDateTime ToLocalDateTime(string text)
        {
            var dateTimeOffset = DeserializeStruct<DateTimeOffset>(text);
            var localDateTime = OffsetDateTime.FromDateTimeOffset(dateTimeOffset).LocalDateTime;
            return localDateTime;
        }

        public static OffsetDateTime ToOffsetDateTime(string text)
        {
            var dateTimeOffset = DeserializeStruct<DateTimeOffset>(text);
            var offsetDateTime = OffsetDateTime.FromDateTimeOffset(dateTimeOffset);
            return offsetDateTime;
        }

        public static ZonedDateTime ToZonedDateTime(string text)
        {
            var dateTimeOffset = DeserializeStruct<DateTimeOffset>(text);
            var zonedDateTime = ZonedDateTime.FromDateTimeOffset(dateTimeOffset);
            return zonedDateTime;
        }

        private static T DeserializeStruct<T>(string text) where T : struct
        {
            var deserializedType = JsonSerializer.DeserializeFromString<T?>(text);

            if (deserializedType == null)
            {
                throw new SerializationException(string.Format("Unable to deserialize to {0}.", typeof (T).Name));
            }

            return deserializedType.Value;
        }
    }
}